package animation;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.Timer;

import routingAlgorithms.RoutingAlgorithm;
import dataobjects.Edge;
import dataobjects.Position;

/**
 * @author Maria Werner
 * @param args
 * @return void
 * This draws a the map and UMVs
 */

//TODO: animate when a seeker dies and remove blown IEDs 

public class AnimatedMap {


	public static Timer t;
	private DrawMap draw;
	private RoutingAlgorithm routingAlgorithm;
	private JButton start = new JButton("Custom Grid Start");
	private JButton random = new JButton("Random Grid Start");
	private JRadioButton ied = new JRadioButton("Add IED");
	private JRadioButton obstacle = new JRadioButton("Add Obstacle");
	private boolean simulation;

	public AnimatedMap(RoutingAlgorithm routingAlgorithm, boolean simulation){
		draw = new DrawMap();
		this.routingAlgorithm = routingAlgorithm;
		this.simulation = simulation;
	}

	public void setUMVPos(int umv, double x, double y){

		draw.setUMVPos(umv, x, y);
	}
	
	public void setUMVDead(int umv){
		draw.setUMVDead(umv);
	}

	public void addIed(Edge edge){
		draw.addIed(edge);
	}

	public void addObstacle(Edge edge){
		draw.addObstacle(edge);
	}

	public void addSafeEdge(Edge edge){
		draw.addSafeEdge(edge);
	}

	public ArrayList<Edge> getObstacles(){
		return draw.getObstacles();
	}

	public ArrayList<Edge> getIeds(){
		return draw.getIeds();
	}

	public void clearAll(){
		draw.clearAll();
	}

	public void resetStartButton(){
		start.setEnabled(true);
		random.setEnabled(true);
		ied.setEnabled(true);
		obstacle.setEnabled(true);

	}

	public void draw() {

		EventQueue.invokeLater(new Runnable(){
			public void run(){
				System.out.println("Running");

				JFrame frame = new JFrame();

				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setTitle("AR2D2 Map");
				frame.setSize(630, 650);
				frame.add(draw);
				frame.setVisible(true);

				if (simulation){

					JFrame controller = new JFrame();
					controller.setTitle("Controller");
					JPanel panel = new JPanel();
					controller.add(panel);
					controller.setVisible(true);
					controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
					controller.setSize(100, 200);
					controller.setLocation(630, 0);
					setup(panel);
					panel.setVisible(true);
				}

			}
		});
	}

	public void setup(JPanel panel){
		ButtonGroup group = new ButtonGroup();
		group.add(ied);
		group.add(obstacle);
		obstacle.setSelected(true);

		start.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {

				Thread t = new Thread(new Runnable(){
					public void run(){
						routingAlgorithm.start(false);
					}
				});
				t.start();
				start.setEnabled(false);
				random.setEnabled(false);
				ied.setEnabled(false);
				obstacle.setEnabled(false);
			}
		});

		random.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {

				Thread t = new Thread(new Runnable(){
					public void run(){
						routingAlgorithm.start(true);
					}
				});
				t.start();
				start.setEnabled(false);
				random.setEnabled(false);
				ied.setEnabled(false);
				obstacle.setEnabled(false);
			}
		});

		obstacle.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				draw.setCreateObstacle(true);
			}

		});

		ied.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				draw.setCreateObstacle(false);
			}

		});

		panel.add(random);
		panel.add(start);
		panel.add(ied);
		panel.add(obstacle);


	}

	public void smoothAnimate(int seekerId, Position oldPos, Position newPos){

		System.out.println("Animating Seeker: "+seekerId);
		final int seekerIdFinal = seekerId;
		final Position oldPosFinal = oldPos;
		final Position newPosFinal = newPos;
		Thread t = new Thread(new Runnable(){
			public void run(){
				for (int i = 0; i < 10; i++){
					double x = oldPosFinal.getX() + (newPosFinal.getX() - oldPosFinal.getX())*i/10.0;
					double y = oldPosFinal.getY() + (newPosFinal.getY() - oldPosFinal.getY())*i/10.0;
					setUMVPos(seekerIdFinal, x, y);
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						///zzzz
					}
				}
			}
		});
		t.start();



	}
}

class Animate implements ActionListener{
	DrawMap map = new DrawMap();
	public Animate(DrawMap map){
		this.map = map;
	}
	@Override
	public void actionPerformed(ActionEvent arg0) {
		map.repaint();
		System.out.println("repaint");
	}

}

class DrawMap extends JComponent{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private double umv1x = 0;
	private double umv2x = 0;
	private double umv3x = 0;
	private double umv1y = 0;
	private double umv2y = 0;
	private double umv3y = 0;
	private double hvax = 0;
	private double hvay = 0;
	private String iedLock = new String("iedLock");
	private String obstacleLock = new String("obstacleLock");
	private String safeLock = new String("safeLock");
	
	private boolean deadUmv1;
	private boolean deadUmv2;
	private boolean deadUmv3;

	private boolean obstacle = true;

	private ArrayList<Edge> ieds = new ArrayList<Edge>();
	private ArrayList<Edge> obstacles = new ArrayList<Edge>();
	private ArrayList<Edge> safe = new ArrayList<Edge>();

	public DrawMap(){
		MouseListener mouseListener = new MyListener(this);
		addMouseListener(mouseListener);
	}

	public void setCreateObstacle(boolean obstacle){
		this.obstacle = obstacle;
	}

	public boolean isCreateObstacle(){
		return obstacle;
	}

	public void setUMVPos(int umv, double x, double y){
		if (umv == 0){
			umv1x = x;
			umv1y = y;
		}
		if (umv == 1){
			umv2x = x;
			umv2y = y;
		}
		if (umv == 2){
			umv3x = x;
			umv3y = y;
		}
		if (umv == -1){

			hvax = x;
			hvay = y;
		}

		repaint();
	}

	public void setUMVDead(int umv){
		if (umv == 0){
			deadUmv1 = true;
		}
		if (umv == 1){
			deadUmv2 = true;
		}
		if (umv == 2){
			deadUmv3 = true;
		}
		repaint();
	}

	public void addIed(Edge edge){
		synchronized(iedLock){
			ieds.add(edge);
		}
		repaint();
	}

	public void addObstacle(Edge edge){
		synchronized(obstacleLock){
			obstacles.add(edge);
		}
		repaint();
	}

	public void addSafeEdge(Edge edge){
		synchronized(safeLock){
			safe.add(edge);
		}
		repaint();
	}

	public ArrayList<Edge> getIeds() {
		return ieds;
	}

	public ArrayList<Edge> getObstacles() {
		return obstacles;
	}

	public void clearAll(){
		ieds.clear();
		obstacles.clear();
		safe.clear();
		umv1x = 0;
		umv2x = 0;
		umv3x = 0;
		umv1y = 0;
		umv2y = 0;
		umv3y = 0;
		hvax = 0;
		hvay = 0;
	}

	@Override
	public void paintComponent(Graphics g){

		Graphics2D g2 = (Graphics2D) g;

		g2.setPaint(Color.BLACK);
		g2.setBackground(Color.WHITE);

		//grid

		for (int i = 0; i < 6; i ++){
			Rectangle2D gridline = new Rectangle2D.Double(i*100+5, 5,10,510);
			g2.fill(gridline);
		}
		for (int i = 0; i < 6; i ++){
			Rectangle2D gridline = new Rectangle2D.Double(5, i*100+5, 500,10);
			g2.fill(gridline);
		}

		synchronized(safeLock){
			//safe Edges
			g2.setPaint(Color.YELLOW);
			for (Edge edge : safe){
				if (edge != null){
					int x = edge.getPos0().getX();
					int y = edge.getPos0().getY();
					int x1 = edge.getPos1().getX();
					int y1 = edge.getPos1().getY();

					Rectangle2D safe = new Rectangle2D.Double((x+x1)/2.0*100-50  + Math.abs(y-y1)*50, 500 - ((y+y1)/2.0*100 - (y-y1)*50), 20+Math.abs(x-x1)*100,20+Math.abs(y-y1)*100);
					g2.fill(safe);
				}
			}
		}

		synchronized(obstacleLock){
			//obstacles
			for (Edge edge : obstacles){
				if (edge != null){
					int x = edge.getPos0().getX();
					int y = edge.getPos0().getY();
					int x1 = edge.getPos1().getX();
					int y1 = edge.getPos1().getY();

					Rectangle2D ied = new Rectangle2D.Double((x+x1)/2.0*100-10, 490 -((y+y1)/2.0*100), 40,40);
					g2.setPaint(Color.WHITE);
					g2.fill(ied);
				}
			}
		}

		synchronized(iedLock){
			//IEDs
			for (Edge edge : ieds){
				if (edge != null){
					int x = edge.getPos0().getX();
					int y = edge.getPos0().getY();
					int x1 = edge.getPos1().getX();
					int y1 = edge.getPos1().getY();

					Rectangle2D ied = new Rectangle2D.Double((x+x1)/2.0*100, 500 - ((y+y1)/2.0*100), 20,20);
					g2.setPaint(Color.RED);
					g2.fill(ied);
				}
			}
		}


		//seekers

		synchronized (this){
			Rectangle2D umv1 = new Rectangle2D.Double(umv1x*100, 500 - umv1y*100, 20,20);
			g2.setPaint(Color.BLUE);
			if (deadUmv1){
				g2.setPaint(Color.GRAY);
			}
			g2.fill(umv1);

			Rectangle2D umv2 = new Rectangle2D.Double(umv2x*100, 500 - umv2y*100, 20,20);
			g2.setPaint(Color.CYAN);
			if (deadUmv2){
				g2.setPaint(Color.GRAY);
			}
			g2.fill(umv2);

			Rectangle2D umv3 = new Rectangle2D.Double(umv3x*100, 500 - umv3y*100, 20,20);
			g2.setPaint(Color.GREEN);
			if (deadUmv3){
				g2.setPaint(Color.GRAY);
			}
			g2.fill(umv3);

			Rectangle2D hva = new Rectangle2D.Double(hvax*100-5, 490 - (hvay*100), 30,30);
			g2.setPaint(Color.MAGENTA);
			g2.fill(hva);
		}
	}

	private static class MyListener implements MouseListener {
		private DrawMap draw;

		MyListener(DrawMap draw){
			this.draw = draw;
		}
		@Override
		public void mouseClicked(MouseEvent arg0) {

			int x = arg0.getX(); 
			int y = arg0.getY(); 

			int xPos = (int) Math.floor(((x - 5)/100.0) + .1);
			int yPos = (int) (5 - Math.floor(((y - 5)/100.0) + .1));

			int xPos2 =  (int) Math.ceil(((x - 5)/100.0) - .1);
			int yPos2 =  (int) (5 - Math.ceil(((y - 5)/100.0) - .1));

			System.out.println("X: "+ x+ " Y: "+y);
			System.out.println("xPos: "+ xPos+ " yPos: "+yPos);
			System.out.println("xPos2: "+ xPos2+ " yPos2: "+yPos2);

			if (draw.isCreateObstacle()){
				draw.addObstacle(new Edge(new Position(xPos, yPos), new Position(xPos2, yPos2)));
			} else {
				draw.addIed(new Edge(new Position(xPos, yPos), new Position(xPos2, yPos2)));
			}
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
		}

		@Override
		public void mouseExited(MouseEvent arg0) {
		}

		@Override
		public void mousePressed(MouseEvent arg0) {
		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
		}

	}
}

